package com.mathdroid.persistence;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import com.mathdroid.core.Config;
import com.mathdroid.exceptionhandling.ExceptionHandler;
import com.mathdroid.model.Profiles;
import com.mathdroid.model.abilities.AbilityTemplates;
import com.mathdroid.model.buffs.BuffTemplates;
import com.mathdroid.model.encounters.EncounterTemplates;
import com.mathdroid.model.enums.ESpec;
import com.mathdroid.model.talents.Specs;

/**
 * The Serializer saves serializable objects to the "data" folders. Also you 
 * can use this class to load objects.
 */
public class Serializer {
	
	/**
	 * The suffix for all saved objects.
	 */
	private static final String SUFFIX = Config.getProperty("suffix");
	
	/**
	 * Serializes objects that do not need a special name.
	 * @param o An serializable object.
	 */
	public final void serialize(final Object o) {
		this.serialize(o, null);
	}
	
	/**
	 * Save an serializable object to the "data" folder. Some objects have a
	 * special other destination. <b>IMPORTANT</b>: Already existent files will 
	 * be overwritten.
	 * @param o An serializable object.
	 * @param name The filename you want without suffix.
	 */
	public final void serialize(final Object o, final String name) {
		String path = "data/";
		
		if (o instanceof Specs) {
			path += "specs/" + name + SUFFIX;
		}
		
		if (o instanceof AbilityTemplates) {
			path += "abilities/" + name + SUFFIX;
		}
		
		if (o instanceof Profiles) {
			path += "profiles" + SUFFIX;
		}
		
		if (o instanceof BuffTemplates) {
			path += "buffs" + SUFFIX;
		}
		
		if (o instanceof EncounterTemplates) {
			path += "encounters" + SUFFIX;
		}
		
		if (path.equals("data/")) {
			path += name + SUFFIX;
		}
		
		try {
			FileOutputStream fileOutput = new FileOutputStream(path);
			ObjectOutputStream objectOutput 
			= new ObjectOutputStream(fileOutput);
			objectOutput.writeObject(o);
		} catch (FileNotFoundException e) {
			ExceptionHandler.report("Could not find file \"" + path + "\".", e);
		} catch (IOException e) {
			ExceptionHandler.report("Could not write to file \"" + path 
					+ "\".", e);
		}
	}

	/**
	 * Load any persistent object.
	 * @param path The relative path to the file.
	 * @return The deserialized object.
	 */
	public final Object deserialize(final String path) {
		Object o = null;
		
		try {
			FileInputStream fileInput = new FileInputStream(path);
			ObjectInputStream objectInput = new ObjectInputStream(fileInput);
			o = objectInput.readObject();
		} catch (FileNotFoundException e) {
			ExceptionHandler.report("Could not find file \"" + path + "\".", e);
		} catch (IOException e) {
			ExceptionHandler.report("Could not write to file \"" + path 
					+ "\".", e);
		} catch (ClassNotFoundException e) {
			ExceptionHandler.report(
					"Could not find class while deserializing.", e);
		}
		
		return o;
	}
	
	/**
	 * Load all talent templates for some specialization.
	 * @param spec The specialization you want talent templates for.
	 * @return The talent templates for the spec.
	 */
	public final Specs getTalentSets(final ESpec spec) {
		return (Specs) this.deserialize(
				"data/specs/" + spec.toString().toLowerCase() + SUFFIX);
	}
	
	/**
	 * Load all ability templates for some specialization.
	 * @param spec The specialization you want ability templates for.
	 * @return The ability templates for the spec.
	 */
	public final AbilityTemplates getAbilitySets(final ESpec spec) {
		return (AbilityTemplates) this.deserialize(
				"data/abilities/" + spec.toString().toLowerCase() + SUFFIX);
	}
	
	/**
	 * Load all saved character profiles.
	 * @return The Profiles object.
	 */
	public final Profiles getProfiles() {
		return (Profiles) this.deserialize("data/profiles" + SUFFIX);
	}
	
	/**
	 * Load all saved buff templates.
	 * @return Buff templates object.
	 */
	public final BuffTemplates getBuffTemplates() {
		return (BuffTemplates) this.deserialize("data/buffs" + SUFFIX);
	}
	
	/**
	 * Load all saved encounter templates.
	 * @return Encounter templates object.
	 */
	public final EncounterTemplates getEncounterTemplates() {
		return (EncounterTemplates) this
			.deserialize("data/encounters" + SUFFIX);
	}
}
